#
# Copyright (c) 2023 supercell
#
# SPDX-License-Identifier: BSD-3-Clause
#

module Luce
  # Parse HTML blocks.
  class HTMLBlockSyntax < BlockSyntax
    # There are seven kinds of HTML block defined in the CommonMark spec:
    # https://spec.commonmark.org/0.30/#html-blocks.
    # These matching conditions and HTML block types mentioned in this syntax
    # correspond to these ones in the CommonMark spec.

    @@end_conditions = [
      # For condition 1, it does not need to match the start tag, see
      # https://spec.commonmark.org/0.30/#end-condition
      Regex.new("</(?:pre|script|style|textarea)>", Regex::Options::IGNORE_CASE),
      Regex.new("-->"),
      Regex.new(%q{\?>}),
      Regex.new(">"),
      Regex.new("]]>"),
      Luce.empty_pattern,
      Luce.empty_pattern,
    ]

    def pattern : Regex
      Luce.html_block_pattern
    end

    def can_end_block?(parser : BlockParser) : Bool
      # All types of HTML blocks except type 7 may interrupt a paragraph, see the
      # second paragraph after https://spec.commonmark.org/0.30/#example-148 for
      # more detail.
      # ameba:disable Lint/NotNil
      pattern.match(parser.current.content).not_nil!["condition_7"]? == nil
    end

    def parse_child_lines(parser : BlockParser) : Array(Line)
      lines = [] of Line

      match = pattern.match(parser.current.content)
      matched_condition = 0
      i = 0
      # ameba:disable Lint/NotNil
      while i < match.not_nil!.group_size
        # ameba:disable Lint/NotNil
        if match.not_nil![i + 1]?.nil?
          i += 1
        else
          matched_condition = i
          break
        end
      end

      end_condition = @@end_conditions[matched_condition]
      if end_condition == Luce.empty_pattern
        lines << parser.current
        parser.advance

        while (!parser.done?) && (!end_condition.matches?(parser.current.content))
          lines << parser.current
          parser.advance
        end
      else
        until parser.done?
          lines << parser.current
          break if end_condition.matches? parser.current.content
          parser.advance
        end
        parser.advance
      end

      # If the current line starts with an HTML block again, put them together with
      # the previous HTML block
      if !parser.done? && pattern.matches?(parser.current.content)
        lines.concat(parse_child_lines(parser))
      end

      lines
    end

    def parse(parser : BlockParser) : Node
      child_lines = parse_child_lines(parser).compact_map { |e| e }

      text = child_lines.map(&.content).join("\n").rstrip
      if !parser.previous_syntax.nil? || !parser.parent_syntax.nil?
        text = "\n#{text}"
        text = "#{text}\n" if parser.parent_syntax.is_a? ListSyntax
      end
      Text.new(text)
    end
  end
end
